#include <QDebug>
#include <QThread>
#include <QDir>
#include "CameraControl.h"
#include "ui_CameraControl.h"
#include "../bin/CamApi.h"

#define MAKETAG(a,b,c,d) (a | (b << 8) | (c << 16) | (d << 24))

const static int GAIN_NUM = 3;
const static int gainValue[GAIN_NUM] = {2,6,10};
const static QString gainString[GAIN_NUM] = {"high gain","low gain","hdr"};

CameraControl::CameraControl(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::CameraControl)
{
    ui->setupUi(this);

    QString fullPath = QDir::currentPath() + "/img/";
    strcpy_s(imagePath, fullPath.toLatin1().data());
    QDir dir(imagePath);
    if(!dir.exists()) {
       dir.mkdir(imagePath);
    }
    InitDevice(imagePath); //初始化设备

    if(DeviceCount()>0)
    {
        DeviceDescriptor(&desc, 0);
        if (NO_SUPPORT == ResumeDevice(desc.name))// ResumeDevice里会默认加载上次退出时参数，或者第一次启动的相机默认参数
        {
            return;
        }
        InitData();
        InitGUI();
    }
    else
    {
        ui->labelDeviceName->setText("No camera!");
        ui->btnLive->setEnabled(false);
    }
}

CameraControl::~CameraControl()
{
    isStop = true;
    ExitDevice();//释放设备
    DeleteData();
    delete ui;
}

void CameraControl::InitData()
{
    if (recvBuf != nullptr)
        delete [] recvBuf;
    recvBuf = new uchar [desc.memSize];
    if (showBuf != nullptr)
        delete [] showBuf;
    showBuf = new uchar [desc.memSize];
}

void CameraControl::DeleteData()
{
    if (recvBuf != nullptr)
        delete [] recvBuf;
    recvBuf = nullptr;
    if (showBuf != nullptr)
        delete [] showBuf;
    showBuf = nullptr;
}

void CameraControl::ROI256()
{
    ui->btnROI->setText("&取消ROI");
    SetAttribute(FW_ROI, S_DEAD, desc.name);
    int width, heigth;
    GetRawSize(&width, &heigth, desc.name);
    printf("before roi, wid is %d, hei is %d\n",width,heigth);

    struct ez_rect roi;
    roi.left = width/2-128;
    roi.right = width/2+128;
    roi.top = heigth/2-127;
    roi.bottom = heigth/2+127;
//        ConvertRect(&roi, 0, wid, hei);
    SetAttribute(AW_RTL, roi.left, desc.name);
    SetAttribute(AW_RTT, roi.top, desc.name);
    SetAttribute(AW_RTR, roi.right, desc.name);
    SetAttribute(AW_RTB, roi.bottom, desc.name);
    SetAttribute(FW_ROI, S_LIVE, desc.name);
    GetRawSize(&width, &heigth, desc.name);
    printf("after roi, wid is %d, hei is %d\n",width,heigth);
}

void CameraControl::UpExposure(float curTime)
{
    ui->doubleSpinBoxMS->setEnabled(true);
    float minTime = GetExposureUnit(desc.name);
    curSec = curTime/1000;
    curMS = curTime-curSec*1000;
    ui->spinBoxSec->setValue(curSec);
    ui->doubleSpinBoxMS->setRange(minTime, 999.99);
    ui->doubleSpinBoxMS->setValue(curMS);
}

void CameraControl::on_cboxRes_currentIndexChanged(int index)
{
    if (index == -1) return;
    struct _ELEMENT node;
    node.id = FW_RES;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        node.val = index;
        SetElement(&node, desc.name);
        ui->cboxRes->setCurrentIndex(node.val);
    }
}

void CameraControl::on_btnLive_clicked()
{
    if (ui->btnLive->text().compare(QString("&启动")))
    {
        ui->btnLive->setText("&启动");
        isStop = true;
    }
    else
    {
        isStop = false;
        ui->btnLive->setText("&停止");
        timeStart = QTime::currentTime();
        std::thread([&]()
        {
            while(!isStop)
            {
                Decode();
            }
            printf("Decode stop\n");

        }).detach();
    }
}

void CameraControl::fpsShow()
{
    fpsCounts++;
    QTime tm = QTime::currentTime();
    int secs = timeStart.secsTo(tm);
    if (secs>1) {
        ui->labelFPS->setNum(double(fpsCounts)/secs);
        rate = fpsCounts/secs;
        fpsCounts = 0;
        timeStart = tm;
    }
}

void CameraControl::InitGUI()
{
    ui->toolBox->setCurrentIndex(0);//显示相机控制界面
    ui->labelDeviceName->setText(desc.name);
    ui->btnLive->setEnabled(true);

    // resolution
    ui->cboxRes->clear();
    struct _ELEMENT node;
    node.id = FW_RES;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        for (int i = 0; i<node.max+1; ++i) {
            char *name = (char *)GetAttribute(FW_RES, ATTR_TXT, i, desc.name);
            ui->cboxRes->addItem(QString(name));
        }
        ui->cboxRes->setCurrentIndex(node.val);
    }

    // exposure
    struct _ELEMENT htm, ltm;
    htm.id = FW_HTM;
    GetElement(&htm, desc.name);
    ltm.id = FW_LTM;
    if (NO_FAIL == GetElement(&ltm, desc.name)) {
        float unit = GetExposureUnit(desc.name);
         UpExposure((htm.val*ltm.max+ltm.val)*unit);
    }

    //ROI
    ROI256();

    //GAIN
    ui->cboxGain->clear();
    for (int i=0;i<GAIN_NUM;i++)
    {
        ui->cboxGain->addItem(gainString[i]);
    }

    //RAW
    int picType = 0;
    picType|=SNAP_RAW;
    int hex = S_LIVE; //  histogram equalization
    SetAttribute(SW_FMT, picType, desc.name);
    SetAttribute(FW_HEX, hex, desc.name);

    // gamma
    node.id = SW_GM0;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        ui->hSliderGamma->setRange(node.min, node.max);
        ui->hSliderGamma->setSingleStep(node.inc);
        ui->hSliderGamma->setValue(node.val);
        ui->labelGamma->setNum(node.val);
    }

    // contrast
    node.id = SW_CON;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        ui->hSliderContrast->setRange(node.min, node.max);
        ui->hSliderContrast->setSingleStep(node.inc);
        ui->hSliderContrast->setValue(node.val);
        ui->labelContrast->setNum(node.val);
    }

    // flip
    node.id = SW_FLP;
    if (NO_FAIL == GetElement(&node, desc.name)) {
//            ui->chcHFlip->setChecked(node.val &FLIP_HORIZONTAL);
//            ui->chcVFlip->setChecked(node.val &FLIP_VERTICAL);
//            ui->chcTFlip->setChecked(node.val &FLIP_TRANSPOSE);
    }

    // snap
    node.id = SW_FMT;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        ui->chcRaw->setChecked(node.val & SNAP_RAW);
        ui->chcJpg->setChecked(node.val  & SNAP_JPG);
        ui->chcBmp->setChecked(node.val  & SNAP_BMP);
        ui->chcTif->setChecked(node.val  & SNAP_TIF);
        ui->chcPng->setChecked(node.val  & SNAP_PNG);
    }
}

void CameraControl::Decode()
{
    uchar *data = nullptr;
    int size = static_cast<int>(desc.memSize);
    int ret = GetRawDataPtr(&data, &(size), desc.name);

    if (ret == NO_FAIL)
    {
        fpsShow();
        printf("the fsd is %d\n",fpsCounts);
        ret = DecodeRaw2Image(data, recvBuf, desc.name);

        if (ret == NO_FAIL)
        {
//                if (pCtx->snap)
//                    {// save image
//                        pCtx->snap = false;
//                        int picType = *(int *)GetAttribute(SW_FMT, ATTR_VAL, 0, desc.name);
//    //                    QString path = pCtx->imagePath;
//                        QString path = QString("D:/img/");
//                        QTime tm = QTime::currentTime();
//                        path.append("p");
//                        path.append(tm.toString());

//                        path = QString("D:/img/dsfgg");
//                        printf("%s\n",path.toLatin1().data());
//                        SaveFile(recvBuf, path.toLatin1().data(), picType);
//                    }

                ConvertXto8(recvBuf, showBuf);

                ImageShow();



             //   if (pCtx->hAvi != 0)
             //       WriteVideo(pCtx->hAvi, (uchar *)pCtx->showBuf);
                // show image
//                if (pCtx->showstate == S_DEAD) {
//                        emit signalShow();
//                }
        }
    }

}

//void EzSample::on_hSliderBklvl_valueChanged(int value)
//{
//}

void CameraControl::on_btnSnap_clicked()
{
    long picType = 0;
    if (ui->chcRaw->isChecked())  picType |= SNAP_RAW;
    if (ui->chcJpg->isChecked())  picType |= SNAP_JPG;
    if (ui->chcBmp->isChecked())  picType |= SNAP_BMP;
    if (ui->chcTif->isChecked())  picType |= SNAP_TIF;
    if (ui->chcPng->isChecked())  picType |= SNAP_PNG;
    SetAttribute(SW_FMT, picType, desc.name);
    snap = true;
}

void CameraControl::on_hSliderGamma_valueChanged(int value)
{
    struct _ELEMENT node;
    node.id = SW_GM0;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        node.val = value;
        SetElement(&node, desc.name);
        ui->labelGamma->setNum(node.val);
    }
}

void CameraControl::on_hSliderContrast_valueChanged(int value)
{
    struct _ELEMENT node;
    node.id = SW_CON;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        node.val = value;
        SetElement(&node, desc.name);
        ui->labelContrast->setNum(node.val);
    }
}

//void EzSample::on_chcHFlip_clicked(bool checked)
//{
//    struct _ELEMENT node;
//    node.id = SW_FLP;
//    if (NO_FAIL == GetElement(&node, desc.name)) {
//        if (checked)  node.val += FLIP_HORIZONTAL;
//        else          node.val -= FLIP_HORIZONTAL;
//        SetElement(&node, desc.name);
//    }
//}

//void EzSample::on_chcVFlip_clicked(bool checked)
//{
//    int flipType = *(int *)GetAttribute(SW_FLP, ATTR_VAL, 0, desc.name);
//    if (checked)  flipType += FLIP_VERTICAL;
//    else          flipType -= FLIP_VERTICAL;
//    SetAttribute(SW_FLP, flipType, desc.name);
//}

//void EzSample::on_chcTFlip_clicked(bool checked)
//{
//    int flipType = *(int *)GetAttribute(SW_FLP, ATTR_VAL, 0, desc.name);
//    if (checked)  flipType += FLIP_TRANSPOSE;
//    else          flipType -= FLIP_TRANSPOSE;
//    SetAttribute(SW_FLP, flipType, desc.name);
//}

void CameraControl::on_spinBoxSec_valueChanged(int arg1)
{
    curSec = arg1;
}

void CameraControl::on_doubleSpinBoxMS_valueChanged(double arg1)
{
    curMS = arg1;
    if (curSec==0) {
        struct _ELEMENT htm, ltm;
        htm.id = FW_HTM;
        GetElement(&htm, desc.name);
        ltm.id = FW_LTM;
        if (NO_FAIL == GetElement(&ltm, desc.name)) {
            float unit = GetExposureUnit(desc.name);
             int counts = curMS/unit;
             htm.val = counts/ltm.max;
             ltm.val = counts%ltm.max;
             SetElement(&htm, desc.name);
             SetElement(&ltm, desc.name);
        }
    }
}

void CameraControl::on_btnApply_clicked()
{
    float exp = curSec*000+curMS;
    struct _ELEMENT htm, ltm;
    htm.id = FW_HTM;
    GetElement(&htm, desc.name);
    ltm.id = FW_LTM;
    if (NO_FAIL == GetElement(&ltm, desc.name)) {
        float unit = GetExposureUnit(desc.name);
         int counts = exp/unit;
         htm.val = counts/ltm.max;
         ltm.val = counts%ltm.max;
         SetElement(&htm, desc.name);
         SetElement(&ltm, desc.name);
    }
}

void CameraControl::on_chkAE_clicked(bool checked)
{
    struct _ELEMENT node;
    node.id = FW_AEX;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        node.val = checked ? S_LIVE : S_DEAD;
        SetElement(&node, desc.name);
        if (checked) {
            ui->spinBoxSec->setEnabled(false);
            ui->doubleSpinBoxMS->setEnabled(false);
        } else {
            struct _ELEMENT htm, ltm;
            htm.id = FW_HTM;
            GetElement(&htm, desc.name);
            ltm.id = FW_LTM;
            if (NO_FAIL == GetElement(&ltm, desc.name)) {
                int counts = htm.val*ltm.max + ltm.val;
                float unit = GetExposureUnit(desc.name);
                UpExposure((htm.val*ltm.max+ltm.val)*unit);
                SetAttribute(FW_HTM, htm.val, desc.name);
                SetAttribute(FW_LTM, ltm.val, desc.name);
            }
        }
    }
}

void CameraControl::on_autolevel_clicked(bool checked)
{
      struct _ELEMENT node;
      node.id = AW_ALV;
      if (NO_FAIL == GetElement(&node, desc.name)) {
          node.val = checked? S_LIVE : S_DEAD;
          SetElement(&node, desc.name);
      }
}

//void EzSample::on_btnVideo_clicked(bool checked)
//{
//    if (ui->btnVideo->text().compare(QString("录像"))) {
//        ui->btnVideo->setText("录像");
//        CloseVideo(handleRecord);
//        ctx.hAvi = 0;
//    } else {
//        ui->btnVideo->setText("停止录像");
//        QDateTime curDateTime=QDateTime::currentDateTime();
//        m_fileNamePrefix = QString("D:/img/video_")+curDateTime.toString("yyyyMMddhhmmss");


//        int wid, hei;
//        GetRawSize(&wid, &hei, desc.name);
////        wid >>= ctx.scale;
////        hei >>= ctx.scale;
//        int codec = /*MAKETAG('M', 'S', 'V', 'C');//*/MAKETAG('D', 'I', 'B', ' ');
//        QString path = m_fileNamePrefix+".avi";
////        OpenVideo(&ctx.hAvi, path.toLatin1().data(), wid, hei, 1, rate, codec);

//        handleRecord = OpenVideo(path.toLatin1().data(), wid, hei, 1, rate,codec);




//    }
//}

void CameraControl::on_btnVideo_clicked()
{

    if (ui->btnVideo->text().compare(QString("录像"))) {
        ui->btnVideo->setText("录像");
        CloseVideo(handleRecord);
        hAvi = nullptr;
    } else {
        ui->btnVideo->setText("停止录像");
        QDateTime curDateTime=QDateTime::currentDateTime();
        m_fileNamePrefix = QString("D:/img/video_")+curDateTime.toString("yyyyMMddhhmmss");


        int wid, hei;
        GetRawSize(&wid, &hei, desc.name);
//        wid >>= ctx.scale;
//        hei >>= ctx.scale;
        int codec = /*MAKETAG('M', 'S', 'V', 'C');//*/MAKETAG('D', 'I', 'B', ' ');
        QString path = m_fileNamePrefix+".avi";
//        OpenVideo(&ctx.hAvi, path.toLatin1().data(), wid, hei, 1, rate, codec);

        handleRecord = OpenVideo(path.toLatin1().data(), wid, hei, 1, rate,codec);




    }
}

void CameraControl::ImageShow()
{
//    showstate = S_LIVE;
//    slotCntShow();
//    showcnts++;
    uchar *buff8 = (uchar *)showBuf;
    uchar *buff16 = (uchar *)recvBuf;
    int width = *(ushort *)(buff8+RAW_OFT_WIDTH);
    int height= *(ushort *)(buff8+RAW_OFT_HEIGHT);
    int offset = *(ushort *)(buff8+RAW_OFT_HEAD);
    QImage image = QImage(buff8+offset, width, height, QImage::Format_Grayscale8);
    image = image.scaled(ui->labelshow->size());
    ui->labelshow->setPixmap(QPixmap::fromImage(image));
  //  printf("%d, %d\n", ctx.showcnts, ctx.deccnts);
//    showstate = S_DEAD;

//    printf("width is %d\n",width);
//    printf("height is %d\n",height);

    if (ui->btnVideo->text().compare(QString("录像")))
    {
        FILE *fp;
        fp = fopen((m_fileNamePrefix + ".dat").toStdString().data(), "ab");
        fwrite(buff16, 2, width * height, fp);
        fclose(fp);

        WriteVideo(handleRecord, buff8);

    }
}

//void EzSample::on_cboxCam_activated(int index)
//{

//}

//void EzSample::on_cboxCam_objectNameChanged(const QString &objectName)
//{

//}

void CameraControl::on_btnROI_clicked()
{
    if (ui->btnROI->text().compare(QString("&ROI"))) {
        SetAttribute(FW_ROI, S_DEAD, desc.name);
        ui->btnROI->setText("&ROI");
    } else {
        ROI256();
//        ui->btnROI->setText("&取消ROI");
    }
}

void CameraControl::on_cboxGain_currentIndexChanged(int index)
{
    if(index<0)
    {
        return;
    }
    struct _ELEMENT node;
    node.id =  FW_AGN;
    if (NO_FAIL == GetElement(&node, desc.name)) {
        node.val = gainValue[index];
        SetElement(&node, desc.name);
    }

}


